#ifndef CPP_GENERATOR_H
#define CPP_GENERATOR_H

#include "code_generator.h"

#include <fstream>
#include <map>

namespace pp
{
    class CppGenerator : public CodeGenerator
    {
    private:
        std::string m_sNameSpace;                               // cpp的namespace，如果为空，则使用m_sPackage
        std::map<std::string, std::string> m_oConstMap;         // 常量所在类
    public:
        CppGenerator(const std::string& srcdir, const std::string& outdir) : CodeGenerator(srcdir, outdir) {}
    public:
        // 重置数据
        virtual void Reset(const std::string& srcfile); // srcfile是pp定义文件名
        // 处理pp文件中的import定义
        virtual void HandleImport(const std::string& imports);
        // 处理pp文件中的option定义，忽略不支持的option。比如option go_package是一个option
        virtual void HandleOption(const std::string& name, const std::string& value);
        // 处理pp文件中的常量定义
        virtual void HandleConst(const std::shared_ptr<FieldInfo>& fieldInfo);
        // 处理pp文件中的enum定义
        virtual void HandleEnum(const std::shared_ptr<StructInfo>& structInfo);
        // 处理pp文件中的message定义
        virtual void HandleStruct(const std::shared_ptr<StructInfo>& structInfo);
        // 生成文件
        virtual void Generate();
    protected:
        // 生成头文件内容
        void GenerateHeadFile(const std::string& outdir, const std::string& filename);
        // 头文件宏定义
        void GenerateHeadMacro(std::ofstream& ofs, const std::string& filename);
        // 头文件include
        void GenerateHeadImport(std::ofstream& ofs);
        // 头文件类声明
        void GenerateHeadClassDeclare(std::ofstream& ofs);
        // 头文件宏定义
        void GenerateHeadConst(std::ofstream& ofs);
        // 头文件枚举定义
        void GenerateHeadEnum(std::ofstream& ofs);
        // 头文件枚举值
        void GenerateHeadEnumValues(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 头文件消息类定义
        void GenerateHeadClass(std::ofstream& ofs);
        // 头文件消息类成员定义
        void GenerateHeadClassAttributes(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 头文件消息类成员Get/Set函数
        void GenerateHeadClassMemberFunctions(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 生成实现文件内容
        void GenerateCppFile(const std::string& outdir, const std::string& filename);
        // CPP文件类实现函数
        void GenerateCppClass(std::ofstream& ofs);
        // CPP文件构造函数
        void GenerateCppClassConstructor(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // CPP文件编码函数
        void GenerateCppClassEncodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // CPP文件解码函数
        void GenerateCppClassDecodeFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // CPP文件ToJson函数
        void GenerateCppClassToJsonFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // CPP文件ToString函数
        void GenerateCppClassToStringFunction(std::ofstream& ofs, const std::vector<std::shared_ptr<FieldInfo> >& vals);
        // 命名空间
        void GenerateNamespace(std::ofstream& ofs);
    protected:
        // 功能函数
        std::string GetFileMacro(const std::string& filename);
        // 命名空间
        std::string GetNameSpace() {return m_sNameSpace.empty() ? m_sPackage : m_sNameSpace;}
        // 命名空间产生的缩进
        std::string GetNameSpaceIndentation() {return GetNameSpace().empty() ? "" : CODE_INDENTATION;}
        // 返回数据类型
        std::string GetClassType(const std::string& ftype);
        // 返回类成员定义
        std::string GetClassAttribute(const std::string& ftype, const std::string& subtype, const std::string& name);
        // 返回类成员名
        std::string GetClassAttributeName(const std::string& ftype, const std::string& subtype, const std::string& name);
        // 返回生成的文件名
        std::string GetHeadFile();
        // 获取常量配置
        const std::map<std::string, std::string>& GetConstMap() const {return m_oConstMap;}
        // 引入其他PP文件定义的常量、message(常量可以在tag，default，size等属性中使用)
        std::string GetImportValue(const std::string& constVal, bool bstring = false);
    };
};

#endif
